/*
 * Simulated browser environment for Rhino
 *   By John Resig <http://ejohn.org/>
 * Copyright 2007 John Resig, under the MIT License
 *
 *
 * $Id: Browser.js 77 2008-09-01 14:45:12Z DeonWu $
 */

var exports = ['window', 'XMLHttpRequest', 'document']

// The window Object
var window = {};
var document = {};

	// Browser Navigator

window.navigator = {
	get userAgent(){
		return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";
	}
};

var curLocation = (new java.io.File("./")).toURL();

window.__defineSetter__("location", function(url){
	var xhr = new XMLHttpRequest();
	xhr.open("GET", url);
	xhr.onreadystatechange = function(){
		curLocation = new java.net.URL( curLocation, url );
		window.document = xhr.responseXML;

		var event = window.document.createEvent();
		event.initEvent("load");
		window.dispatchEvent( event );
	};
	xhr.send();
});

window.__defineGetter__("location", function(url){
	return {
		get protocol(){
			return curLocation.getProtocol() + ":";
		},
		get href(){
			return curLocation.toString();
		},
		toString: function(){
			return this.href;
		}
	};
});

// Timers

var timers = [];

window.setTimeout = function(fn, time){
	var num;
	return num = setInterval(function(){
		fn();
		clearInterval(num);
	}, time);
};

window.setInterval = function(fn, time){
	var num = timers.length;
	
	timers[num] = new java.lang.Thread(new java.lang.Runnable({
		run: function(){
			while (true){
				java.lang.Thread.currentThread().sleep(time);
				fn();
			}
		}
	}));
	
	timers[num].start();

	return num;
};

window.clearInterval = function(num){
	if ( timers[num] ) {
		timers[num].stop();
		delete timers[num];
	}
};

// Window Events

var events = [{}];

window.addEventListener = function(type, fn){
	if ( !this.uuid || this == window ) {
		this.uuid = events.length;
		events[this.uuid] = {};
	}
   
	if ( !events[this.uuid][type] )
		events[this.uuid][type] = [];
	
	if ( events[this.uuid][type].indexOf( fn ) < 0 )
		events[this.uuid][type].push( fn );
};

window.removeEventListener = function(type, fn){
   if ( !this.uuid || this == window ) {
       this.uuid = events.length;
       events[this.uuid] = {};
   }
   
   if ( !events[this.uuid][type] )
		events[this.uuid][type] = [];
		
	events[this.uuid][type] =
		events[this.uuid][type].filter(function(f){
			return f != fn;
		});
};

window.dispatchEvent = function(event){
	if ( event.type ) {
		if ( this.uuid && events[this.uuid][event.type] ) {
			var self = this;
		
			events[this.uuid][event.type].forEach(function(fn){
				fn.call( self, event );
			});
		}
		
		if ( this["on" + event.type] )
			this["on" + event.type].call( self, event );
	}
};

// DOM Document

window.DOMDocument = function(file){
	this._file = file;
	this._dom = Packages.javax.xml.parsers.
		DocumentBuilderFactory.newInstance()
			.newDocumentBuilder().parse(file);
	
	if ( !obj_nodes.containsKey( this._dom ) )
		obj_nodes.put( this._dom, this );
};

window.DOMDocument.prototype = {
	createTextNode: function(text){
		return makeNode( this._dom.createTextNode(
			text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
	},
	createElement: function(name){
		return makeNode( this._dom.createElement(name.toLowerCase()) );
	},
	getElementsByTagName: function(name){
		return new window.DOMNodeList( this._dom.getElementsByTagName(
			name.toLowerCase()) );
	},
	getElementById: function(id){
		var elems = this._dom.getElementsByTagName("*");
		
		for ( var i = 0; i < elems.length; i++ ) {
			var elem = elems.item(i);
			if ( elem.getAttribute("id") == id )
				return makeNode(elem);
		}
		
		return null;
	},
	get body(){
		return this.getElementsByTagName("body")[0];
	},
	get documentElement(){
		return makeNode( this._dom.getDocumentElement() );
	},
	get ownerDocument(){
		return null;
	},
	addEventListener: window.addEventListener,
	removeEventListener: window.removeEventListener,
	dispatchEvent: window.dispatchEvent,
	get nodeName() {
		return "#document";
	},
	importNode: function(node, deep){
		return makeNode( this._dom.importNode(node._dom, deep) );
	},
	toString: function(){
		return "Document" + (typeof this._file == "string" ?
			": " + this._file : "");
	},
	get innerHTML(){
		return this.documentElement.outerHTML;
	},
	
	get defaultView(){
		return {
			getComputedStyle: function(elem){
				return {
					getPropertyValue: function(prop){
						prop = prop.replace(/\-(\w)/g,function(m,c){
							return c.toUpperCase();
						});
						var val = elem.style[prop];
						
						if ( prop == "opacity" && val == "" )
							val = "1";
							
						return val;
					}
				};
			}
		};
	},
	
	createEvent: function(){
		return {
			type: "",
			initEvent: function(type){
				this.type = type;
			}
		};
	}
};

function getDocument(node){
	return obj_nodes.get(node);
}

// DOM NodeList

window.DOMNodeList = function(list){
	this._dom = list;
	this.length = list.getLength();
	
	for ( var i = 0; i < this.length; i++ ) {
		var node = list.item(i);
		this[i] = makeNode( node );
	}
};

window.DOMNodeList.prototype = {
	toString: function(){
		return "[ " +
			Array.prototype.join.call( this, ", " ) + " ]";
	},
	get outerHTML(){
		return Array.prototype.map.call(
			this, function(node){return node.outerHTML;}).join('');
	}
};

// DOM Node

window.DOMNode = function(node){
	this._dom = node;
};

window.DOMNode.prototype = {
	get nodeType(){
		return this._dom.getNodeType();
	},
	get nodeValue(){
		return this._dom.getNodeValue();
	},
	get nodeName() {
		return this._dom.getNodeName();
	},
	cloneNode: function(deep){
		return makeNode( this._dom.cloneNode(deep) );
	},
	get ownerDocument(){
		return getDocument( this._dom.ownerDocument );
	},
	get documentElement(){
		return makeNode( this._dom.documentElement );
	},
	get parentNode() {
		return makeNode( this._dom.getParentNode() );
	},
	get nextSibling() {
		return makeNode( this._dom.getNextSibling() );
	},
	get previousSibling() {
		return makeNode( this._dom.getPreviousSibling() );
	},
	toString: function(){
		return '"' + this.nodeValue + '"';
	},
	get outerHTML(){
		return this.nodeValue;
	}
};

// DOM Element

window.DOMElement = function(elem){
	this._dom = elem;
	this.style = {
		get opacity(){ return this._opacity; },
		set opacity(val){ this._opacity = val + ""; }
	};
	
	// Load CSS info
	var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
	
	for ( var i = 0; i < styles.length; i++ ) {
		var style = styles[i].split(/\s*:\s*/);
		if ( style.length == 2 )
			this.style[ style[0] ] = style[1];
	}
};

window.DOMElement.prototype = extend( new window.DOMNode(), {
	get nodeName(){
		return this.tagName.toUpperCase();
	},
	get tagName(){
		return this._dom.getTagName();
	},
	toString: function(){
		return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
	},
	get outerHTML(){
		var ret = "<" + this.tagName, attr = this.attributes;
		
		for ( var i in attr )
			ret += " " + i + "='" + attr[i] + "'";
			
		if ( this.childNodes.length || this.nodeName == "SCRIPT" )
			ret += ">" + this.childNodes.outerHTML + 
				"</" + this.tagName + ">";
		else
			ret += "/>";
		
		return ret;
	},
	
	get attributes(){
		var attr = {}, attrs = this._dom.getAttributes();
		
		for ( var i = 0; i < attrs.getLength(); i++ )
			attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
			
		return attr;
	},
	
	get innerHTML(){
		return this.childNodes.outerHTML;	
	},
	set innerHTML(html){
		html = html.replace(/<\/?([A-Z]+)/g, function(m){
			return m.toLowerCase();
		});
		
		var nodes = this.ownerDocument.importNode(
			new window.DOMDocument( new java.io.ByteArrayInputStream(
				(new java.lang.String("<wrap>" + html + "</wrap>"))
					.getBytes("UTF8"))).documentElement, true).childNodes;
			
		while (this.firstChild)
			this.removeChild( this.firstChild );
		
		for ( var i = 0; i < nodes.length; i++ )
			this.appendChild( nodes[i] );
	},
	
	get textContent(){
		return nav(this.childNodes);
		
		function nav(nodes){
			var str = "";
			for ( var i = 0; i < nodes.length; i++ )
				if ( nodes[i].nodeType == 3 )
					str += nodes[i].nodeValue;
				else if ( nodes[i].nodeType == 1 )
					str += nav(nodes[i].childNodes);
			return str;
		}
	},
	set textContent(text){
		while (this.firstChild)
			this.removeChild( this.firstChild );
		this.appendChild( this.ownerDocument.createTextNode(text));
	},
	
	style: {},
	clientHeight: 0,
	clientWidth: 0,
	offsetHeight: 0,
	offsetWidth: 0,
	
	get disabled() {
		var val = this.getAttribute("disabled");
		return val != "false" && !!val;
	},
	set disabled(val) { return this.setAttribute("disabled",val); },
	
	get checked() {
		var val = this.getAttribute("checked");
		return val != "false" && !!val;
	},
	set checked(val) { return this.setAttribute("checked",val); },
	
	get selected() {
		if ( !this._selectDone ) {
			this._selectDone = true;
			
			if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
				var opt = this.parentNode.getElementsByTagName("option");
				
				if ( this == opt[0] ) {
					var select = true;
					
					for ( var i = 1; i < opt.length; i++ )
						if ( opt[i].selected ) {
							select = false;
							break;
						}
						
					if ( select )
						this.selected = true;
				}
			}
		}
		
		var val = this.getAttribute("selected");
		return val != "false" && !!val;
	},
	set selected(val) { return this.setAttribute("selected",val); },

	get className() { return this.getAttribute("class") || ""; },
	set className(val) {
		return this.setAttribute("class",
			val.replace(/(^\s*|\s*$)/g,""));
	},
	
	get type() { return this.getAttribute("type") || ""; },
	set type(val) { return this.setAttribute("type",val); },
	
	get value() { return this.getAttribute("value") || ""; },
	set value(val) { return this.setAttribute("value",val); },
	
	get src() { return this.getAttribute("src") || ""; },
	set src(val) { return this.setAttribute("src",val); },
	
	get id() { return this.getAttribute("id") || ""; },
	set id(val) { return this.setAttribute("id",val); },
	
	getAttribute: function(name){
		return this._dom.hasAttribute(name) ?
			new String( this._dom.getAttribute(name) ) :
			null;
	},
	setAttribute: function(name,value){
		this._dom.setAttribute(name,value);
	},
	removeAttribute: function(name){
		this._dom.removeAttribute(name);
	},
	
	get childNodes(){
		return new window.DOMNodeList( this._dom.getChildNodes() );
	},
	get firstChild(){
		return makeNode( this._dom.getFirstChild() );
	},
	get lastChild(){
		return makeNode( this._dom.getLastChild() );
	},
	appendChild: function(node){
		this._dom.appendChild( node._dom );
	},
	insertBefore: function(node,before){
		this._dom.insertBefore( node._dom, before ? before._dom : before );
	},
	removeChild: function(node){
		this._dom.removeChild( node._dom );
	},

	getElementsByTagName: window.DOMDocument.prototype.getElementsByTagName,
	
	addEventListener: window.addEventListener,
	removeEventListener: window.removeEventListener,
	dispatchEvent: window.dispatchEvent,
	
	click: function(){
		var event = window.document.createEvent();
		event.initEvent("click");
		this.dispatchEvent(event);
	},
	submit: function(){
		var event = window.document.createEvent();
		event.initEvent("submit");
		this.dispatchEvent(event);
	},
	focus: function(){
		var event = window.document.createEvent();
		event.initEvent("focus");
		this.dispatchEvent(event);
	},
	blur: function(){
		var event = window.document.createEvent();
		event.initEvent("blur");
		this.dispatchEvent(event);
	},
	get elements(){
		return this.getElementsByTagName("*");
	},
	get contentWindow(){
		return this.nodeName == "IFRAME" ? {
			document: this.contentDocument
		} : null;
	},
	get contentDocument(){
		if ( this.nodeName == "IFRAME" ) {
			if ( !this._doc )
				this._doc = new window.DOMDocument(
					new java.io.ByteArrayInputStream((new java.lang.String(
					"<html><head><title></title></head><body></body></html>"))
					.getBytes("UTF8")));
			return this._doc;
		} else
			return null;
	}
});

// Helper method for extending one object with another

function extend(a,b) {
	for ( var i in b ) {
		var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
		
		if ( g || s ) {
			if ( g )
				a.__defineGetter__(i, g);
			if ( s )
				a.__defineSetter__(i, s);
		} else
			a[i] = b[i];
	}
	return a;
}

// Helper method for generating the right
// DOM objects based upon the type

var obj_nodes = new java.util.HashMap();

function makeNode(node){
	if ( node ) {
		if ( !obj_nodes.containsKey( node ) )
			obj_nodes.put( node, node.getNodeType() == 
				Packages.org.w3c.dom.Node.ELEMENT_NODE ?
					new window.DOMElement( node ) : new window.DOMNode( node ) );
		
		return obj_nodes.get(node);
	} else
		return null;
}

// XMLHttpRequest
// Originally implemented by Yehuda Katz

var XMLHttpRequest = function(){
	this.headers = {};
	this.responseHeaders = {};
};

XMLHttpRequest.prototype = {
	open: function(method, url, async, user, password){ 
		this.readyState = 1;
		if (async)
			this.async = true;
		this.method = method || "GET";
		this.url = url;
		this.onreadystatechange();
	},
	setRequestHeader: function(header, value){
		this.headers[header] = value;
	},
	getResponseHeader: function(header){ },
	send: function(data){
		var self = this;
		
		function makeRequest(){
			var url = new java.net.URL(curLocation, self.url);
			
			if ( url.getProtocol() == "file" ) {
				if ( self.method == "PUT" ) {
					var out = new java.io.FileWriter( 
							new java.io.File( new java.net.URI( url.toString() ) ) ),
						text = new java.lang.String( data || "" );
					
					out.write( text, 0, text.length() );
					out.flush();
					out.close();
				} else if ( self.method == "DELETE" ) {
					var file = new java.io.File( new java.net.URI( url.toString() ) );
					file["delete"]();
				} else {
					var connection = url.openConnection();
					connection.connect();
					handleResponse();
				}
			} else { 
				var connection = url.openConnection();
				
				connection.setRequestMethod( self.method );
				
				// Add headers to Java connection
				for (var header in self.headers)
					connection.addRequestProperty(header, self.headers[header]);
			
				connection.connect();
				
				// Stick the response headers into responseHeaders
				for (var i = 0; ; i++) { 
					var headerName = connection.getHeaderFieldKey(i); 
					var headerValue = connection.getHeaderField(i); 
					if (!headerName && !headerValue) break; 
					if (headerName)
						self.responseHeaders[headerName] = headerValue;
				}
				
				handleResponse();
			}
			
			function handleResponse(){
				self.readyState = 4;
				self.status = parseInt(connection.responseCode) || undefined;
				self.statusText = connection.responseMessage || "";
				
				var stream = new java.io.InputStreamReader(connection.getInputStream()),
					buffer = new java.io.BufferedReader(stream), line;
				
				while ((line = buffer.readLine()) != null)
					self.responseText += line;
					
				self.responseXML = null;
				
				if ( self.responseText.match(/^\s*</) ) {
					try {
						self.responseXML = new window.DOMDocument(
							new java.io.ByteArrayInputStream(
								(new java.lang.String(
									self.responseText)).getBytes("UTF8")));
					}catch(e){
						print(e.toString())
					}
				}
			}
			
			self.onreadystatechange();
		}

		if (this.async)
			(new java.lang.Thread(new java.lang.Runnable({
				run: makeRequest
			}))).start();
		else
			makeRequest();
	},
	abort: function(){},
	onreadystatechange: function(){},
	getResponseHeader: function(header){
		if (this.readyState < 3)
			throw new Error("INVALID_STATE_ERR");
		else {
			var returnedHeaders = [];
			for (var rHeader in this.responseHeaders) {
				if (rHeader.match(new Regexp(header, "i")))
					returnedHeaders.push(this.responseHeaders[rHeader]);
			}
		
			if (returnedHeaders.length)
				return returnedHeaders.join(", ");
		}
		
		return null;
	},
	getAllResponseHeaders: function(header){
		if (this.readyState < 3)
			throw new Error("INVALID_STATE_ERR");
		else {
			var returnedHeaders = [];
			
			for (var header in this.responseHeaders)
				returnedHeaders.push( header + ": " + this.responseHeaders[header] );
			
			return returnedHeaders.join("\r\n");
		}
	},
	async: false,
	readyState: 0,
	responseText: "",
	status: 0
};

//scope is passed by __import__ functional.  import 'document' to scope, the 
//document is referenced to document attribute in window object.
if(typeof(scope) == 'object'){
	scope.__defineGetter__('document', function(){
			return window.document;
	});
	scope.__defineSetter__('document', function(val){
			return null;
			//return window.document;
	});	
}
